/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.neuralstudio.utils;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import org.jane.core.Neuron;
import org.jane.core.layers.SimpleLayer;
import org.jane.core.networks.AbstractNeuralNetwork;
import org.jane.core.networks.AbstractSupervisedNeuralNetwork;
import org.jane.core.networks.AbstractUnsupervisedNeuralNetwork;
import org.jane.core.networks.Adaline;
import org.jane.core.networks.CompetitiveNetwork;
import org.jane.core.networks.KohonenSelfOrganizingMap;
import org.jane.core.networks.MultiLayerPerceptron;
import org.jane.core.networks.Perceptron;
import org.jane.core.networks.SingleLayerFeedForwardNetwork;
import org.jane.utils.AbstractDataset;
import org.jane.utils.SupervisedDataset;
import org.jane.utils.UnsupervisedDataset;
import org.jane.utils.VectorUtils;
import org.math.plot.Plot2DPanel;
import org.math.plot.Plot3DPanel;
import org.math.plot.PlotPanel;

/**
 *
 * @author william
 */
public class ClassificationTrainerThread extends Thread{
    private AbstractNeuralNetwork net;
    private int iterations;
    private AbstractDataset dataset;
    private PlotPanel plotPanel;
    
    private final JProgressBar bar;
    private double[] iter;
    private double[] errors;
    private final Float minError;
    private List<List<List<Float>>> categorizedData;
    private List<Color> colors;
    private final JTextArea textArea;
    private int index;
    private final JButton button;

    public ClassificationTrainerThread(AbstractDataset dataset,PlotPanel plotPanel, AbstractNeuralNetwork net,
            int iterations, Float minError,JProgressBar bar,List<Color> colors, JTextArea textArea,JButton button) {
        this.net = net;
        this.dataset = dataset;
        this.plotPanel = plotPanel;
        this.iterations = iterations;
        this.minError = minError;
        this.textArea = textArea;
        this.bar = bar;
        this.colors = colors;
        this.button = button;
        initializeCategories();

    }
    private void initializeCategories() {
        if (this.net instanceof KohonenSelfOrganizingMap) {
            this.categorizedData = new ArrayList<List<List<Float>>>();
            for (int i = 0; i < ((KohonenSelfOrganizingMap)net).getLayerSize(); i++) {
                this.categorizedData.add(new ArrayList<List<Float>>());
            }
        }
         if (this.net instanceof CompetitiveNetwork) {
            this.categorizedData = new ArrayList<List<List<Float>>>();
            for (int i = 0; i < ((CompetitiveNetwork)net).getLayerSize(); i++) {
                this.categorizedData.add(new ArrayList<List<Float>>());
            }
        }
    }
    public void run() {
        try {
            if (net instanceof MultiLayerPerceptron || net instanceof Adaline || net instanceof Perceptron) {
                for (int i = 0; i < iterations; i++){
                    index = i;
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            bar.setValue(index);
                        }
                    });
                    ((AbstractSupervisedNeuralNetwork)net).train(((SupervisedDataset)dataset).getData());
                }
            }else{
                 for (int h = 0; h < iterations; h++){
                    initializeCategories();
                    for (int i = 0; i < ((UnsupervisedDataset)dataset).getData().size(); i++) {
                        List<Float> results = ((AbstractUnsupervisedNeuralNetwork)net).processData(VectorUtils.normalize(((UnsupervisedDataset)dataset).getDataRow(i)));
                        index = h;
                        SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                bar.setValue(index);
                            }
                        });
                        if (((UnsupervisedDataset)dataset).getInputSize() == 2 || ((UnsupervisedDataset)dataset).getInputSize() == 3) {
                            int j = 0;
                            for (Float r : results) {
                                if (r != 0) {
                                    this.categorizedData.get(j).add(((UnsupervisedDataset)dataset).getDataRow(i));
                                }
                                j++;
                            }
                        }
                    }
                 }
            }

            SwingUtilities.invokeLater(new Runnable() {

                public void run() {
                    //bar.setIndeterminate(false);
                    if (net instanceof AbstractUnsupervisedNeuralNetwork &&(((UnsupervisedDataset)dataset).getInputSize() == 2 || ((UnsupervisedDataset)dataset).getInputSize() == 3)) {

                        int j = 0;
                        if (colors.size() == 0) {
                            for (int k = 0; k < categorizedData.size(); k++) {
                                colors.add(new Color((float)Math.random(),(float)Math.random(),(float)Math.random()));
                            }
                        }
                        int i = 0;
                        List<List<Float>> weights = ((AbstractUnsupervisedNeuralNetwork)net).getWeightVectors();


                        double v[][] = new double[weights.size()][weights.get(0).size()];
                        double[] originPlot = new double[weights.size()];
                        for (List<Float> w : weights) {
                            originPlot[i] = 0;
                            v[i][0] = w.get(0);
                            v[i][1] = w.get(1);
                            if (w.size() == 3)
                                v[i][1] = w.get(2);
                            /*
                            double x[] = new double[weights.size()];
                            double y[] = new double[weights.size()];
                            double z[] = new double[weights.size()];
                            x[0] = w.get(0);
                            y[1] = w.get(1);
                            if (w.size() == 3)
                                z[2] = w.get(2);
                             *
                             */

                            i++;
                        }

                        if (plotPanel instanceof Plot2DPanel) {
                            //((Plot2DPanel)plotPanel).addLinePlot("Vector "+i, x, y);
                            ((Plot2DPanel)plotPanel).addScatterPlot("Origen", originPlot, originPlot);
                            ((Plot2DPanel)plotPanel).addVectortoPlot(0, v);
                        }else{
                            //((Plot3DPanel)plotPanel).addLinePlot("Vector "+i, x, y, z);
                            //((Plot3DPanel)plotPanel).addScatterPlot("Origen", originPlot, originPlot, originPlot);
                            //((Plot3DPanel)plotPanel).addVectortoPlot(0, v);
                        }
                        textArea.append(System.getProperty("line.separator"));
                        textArea.append("*******Datos Clasificados*******");
                        textArea.append(System.getProperty("line.separator"));
                        for(List<List<Float>> category : categorizedData){
                            if (!category.isEmpty()) {
                            double[][] xy = new double[category.size()][2];
                            /*double[] x = new double[category.size()];
                            double[] y = new double[category.size()];
                            double[] z = null;*/

                            textArea.append("Categoria: ");
                            textArea.append(category.toString());
                            textArea.append(System.getProperty("line.separator"));
                            if (((UnsupervisedDataset)dataset).getInputSize() == 3){}
                                //z = new double[category.size()];
                            i = 0;
                            for(List<Float> dataRow : category) {
                                xy[i][0] = dataRow.get(0);
                                xy[i][1] = dataRow.get(1);
                                /*
                                x[i] = dataRow.get(0);
                                y[i] = dataRow.get(1);
                                 *
                                 */
                                if (((UnsupervisedDataset)dataset).getInputSize() == 3) {
                                    //z[i] = dataRow.get(2);
                                }
                                i++;
                            }
                            if (plotPanel instanceof Plot2DPanel) {
                                try {
                                    ((Plot2DPanel)plotPanel).addScatterPlot("Categoria: "+j,colors.get(j), xy);
                                }catch(Exception e){
                                    /*System.out.println(e.toString());
                                    System.out.println("datos:");
                                    for(double[] pair : xy) {
                                    for(double val : pair) {
                                    System.out.print(val+" ");
                                    }
                                    System.out.println();
                                    }
                                    System.out.println(category);*/

                                }
                            }
                            if (plotPanel instanceof Plot3DPanel) {
                                //((Plot3DPanel)plotPanel).addScatterPlot("Categoria: "+j, colors.get(j), x, y, z);
                            }
                            j++;
                        }
                        }
                    }
                    if (net instanceof MultiLayerPerceptron || net instanceof Adaline || net instanceof Perceptron || dataset.getInputSize() == 1) {
                        /*
                        double[][] data = new double[dataset.size()][2];
                        int j = 0;
                        for (List<List<Float>> dataRow : ((SupervisedDataset)dataset).getData()) {
                            data[j][0] = dataRow.get(0).get(0);
                            data[j][1] = dataRow.get(1).get(0);
                        }
                        ((Plot2DPanel)plotPanel).addScatterPlot("Datos", data);
                         *
                         */
                        if (net instanceof SingleLayerFeedForwardNetwork) {

                                SimpleLayer neurons = ((SingleLayerFeedForwardNetwork)net).getNeurons();
                                for(int i = 0; i < neurons.getSize(); i++) {
                                    double[][] boundariesData = new double[2][2];
                                    Neuron neuron = neurons.getNeuron(i);
                                    boundariesData[0][0] = -neuron.getBias()/neuron.getWeights().get(0);
                                    boundariesData[1][1] = -neuron.getBias()/neuron.getWeights().get(1);
                                    ((Plot2DPanel)plotPanel).addLinePlot("Fronteras de decisión", boundariesData);
                                }


                        }
                    }
                    /*
                    if (dataset instanceof UnsupervisedDataset) {
                        if (plotPanel instanceof Plot2DPanel) {
                            List<List<Float>> weights = ((CompetitiveNetwork)net).getWeightVectors();
                            double[][] vectorsArray = new double[weights.size()][2];
                            int i = 0;
                            for (List<Float> vector : weights) {
                                vectorsArray[i][0] = vector.get(0);
                                vectorsArray[i][1] = vector.get(1);
                                i++;
                            }
                            ((Plot2DPanel)plotPanel).addVectortoPlot(0, vectorsArray);
                        }
                        if (plotPanel instanceof Plot3DPanel) {
                            //((Plot3DPanel)plotPanel).addvaddVectortoPlot(iterations, v)addScatterPlot("Entradas", Color.blue, x, y, z);
                        }
                    }
                     *
                     */
                    ((JPanel)plotPanel.getParent()).revalidate();
                    plotPanel.getParent().repaint();
                    button.setEnabled(true);
                }


            });
        }catch(Exception e){System.out.println(e.toString());}

    }
    

}
